
use axum::middleware;
use axum_login::{
    login_required,
    tower_sessions::{ExpiredDeletion, Expiry, SessionManagerLayer},
    AuthManagerLayerBuilder,
};
use axum_messages::MessagesManagerLayer;
use sqlx::SqlitePool;
use time::Duration;
use tokio::{signal, task::AbortHandle};
use tower_sessions::cookie::Key;
use tower_sessions_sqlx_store::SqliteStore;

use crate::{
    logdb, lolcate, rbac, users::Backend, web::{admin, auth, casbinauthz, log, protected::{self, casbin_middleware}, showlove}
};

use getifaddrs::getifaddrs;
use std::net::{IpAddr};
use std::process::Command;

use std::env;
use std::{
    fs,
    io,
    path::{PathBuf},
};
use axum::{
    extract::{DefaultBodyLimit},
};

use std::{io::prelude::*};
use tower_http::services::ServeDir;
use axum::Router;

use http::{header::{CONTENT_TYPE, HeaderValue}};
use tower_http::set_header::SetResponseHeaderLayer;
use tower::ServiceBuilder;
// 配置结构
struct LocalConfig {
    root_dir: String,
    address: String,
}

// 读取配置文件
fn read_config() -> io::Result<LocalConfig> {
    // 实际实现中可能从文件读取，这里简化为硬编码
    Ok(LocalConfig {
        root_dir: crate::util::path_normalization(crate::util::get_system_root()),
        address: "0.0.0.0:18516".to_string(),
    })
}


fn open_browser(url: &str) -> Result<(), Box<dyn std::error::Error>> {
    #[cfg(target_os = "linux")]
    {
        // Step 1: Run `xhost +` to allow access to the X Server
        println!("Granting X Server access with `xhost +`...");
        let xhost_output = Command::new("sh")
            .arg("-c")
            .arg("xhost +") // Run as current user (not root)
            .status()
            .expect("Failed to execute `xhost +`");

        if !xhost_output.success() {
            eprintln!("Error: `xhost +` failed. Check X Server configuration.");
            return Ok(());
        }
        let browsers = vec![
            "firefox",
            "google-chrome",
            "chromium"
        ];
        
        for browser in browsers {
            let status = Command::new(browser)
                .arg(url)
                .status()?;
                
            if status.success() {
                println!("浏览器已启动，访问: {}", url);
                return Ok(());
            }
        }
        
        Err("所有浏览器尝试均失败".into())
    }
    
    #[cfg(target_os = "windows")]
    {
        // Windows实现
        // 使用opener crate打开浏览器
        if let Err(e) = opener::open(&url) {
            eprintln!("无法打开浏览器: {}", e);
            eprintln!("请手动访问: {}", url);
            Err("无法打开浏览器".into())
        } else {
            println!("WINDOWS浏览器已启动，访问: {}", url);
            Ok(())
        }
    }
    
    #[cfg(target_os = "macos")]
    {
        // macOS实现
        // 使用opener crate打开浏览器
        if let Err(e) = opener::open(&url) {
            eprintln!("无法打开浏览器: {}", e);
            eprintln!("请手动访问: {}", url);
        } else {
            println!("浏览器已启动，访问: {}", url);
        }
    }
}
fn replace_dirs_with_current() -> String {
    // 获取当前目录并转换为字符串
    let current_dir: PathBuf = env::current_dir()
        .expect("无法获取当前目录");
    
    // 将路径转换为字符串并处理特殊字符
    let current_dir_str = current_dir.to_string_lossy().replace("\\", "\\\\");
    
    let start = r#"
description = ""

# Directories to index.
dirs = [
    "#;
    
    let tail = r#" 
]

# Set to "Dirs" or "Files" to skip directories or files.
# If unset, or set to "None", both files and directories will be included.
# skip = "Dirs"

# Set to true if you want skip symbolic links
ignore_symlinks = false

# Set to true if you want to ignore hidden files and directories
ignore_hidden = false

# Set to true to read .gitignore files and ignore matching files
gitignore = false

"#;
    
    // 使用字符串格式化进行拼接
    let config = format!("{}{:?}{}", start, current_dir_str, tail);
    
    println!("替换目录后的配置:\n{}", config);
    
    config
}


pub struct App {
    db: SqlitePool,
}

impl App {
    pub async fn new() -> Result<Self, Box<dyn std::error::Error>> {
        // 构建数据库路径（使用当前工作目录）
        let db_path = std::env::current_dir()?
            .join("users.db");
        
        // 确保目录存在
        if let Some(parent) = db_path.parent() {
            std::fs::create_dir_all(parent)?;
        }
    // 检查文件是否存在（可选，SQLite 会自动创建）
        if !db_path.exists() {
            // 手动创建空文件（SQLite 会自动处理，但这步可提供更明确的错误）
            std::fs::File::create(&db_path)?;
            
            println!("Created new database file: {}", db_path.display());
        } else {
            //println!("Using existing database file: {}", db_path.display());
        }
        // 创建数据库连接池
        let db_url = db_path.to_str();
        let db = SqlitePool::connect(db_url.expect("not-found")).await?;
        sqlx::migrate!().run(&db).await?;

        Ok(Self { db })
    }

    pub async fn serve(&self) -> Result<(), Box<dyn std::error::Error>> {
        
        rbac::create_enforcer().await;
        // 启动定期删除日志任务
        tokio::spawn(logdb::delete_old_logs());
        // 读取配置文件
        let config = read_config().expect("Failed to read config");

        // 创建上传目录
        let upload_dir = PathBuf::from(&config.root_dir).join("uploads");
        if !upload_dir.exists() {
            std::fs::create_dir_all(&upload_dir).expect("Failed to create upload directory");
        }

        let current_dir = std::env::current_dir().expect("无法获取当前目录");
        let file_path = current_dir.join("lolversion");

        if std::path::Path::new(&file_path).exists() {
            println!("当前目录存在 'lolversion' 文件");
            // periodic update task.
            // lolcate::create_global_config_if_needed().unwrap();

            // let databases: Vec<String> = lolcate::database_names(lolcate::lolcate_config_path());
            // lolcate::update_databases(databases).unwrap();
        } else {
            //如果当前没有lolversion文件。执行下面操作。
            //如果当前没有配置文件就创建配置文件，如果有配置文件，将当前目录放到配置文件中。创建数据库。

            //如果当前已经有配置文件就只将当前目录放到配置文件中。创建数据库。

            //更新数据库。

            //更新完成后，将数据库时间做一下标记，放在lolversion中。内容为当前日期。

            //每天更新一次。更新后日期放在lolversion中。
            match lolcate::create_global_config_if_needed() {
                Ok(_) => println!("lolcate global config 创建成功"),
                Err(e) => {
                    eprintln!("lolcate global config 创建时发生错误: {}", e);
                    // 可以在这里添加更多错误处理逻辑
                    // 例如返回错误代码或进行重试
                }
            }
            //let databases: Vec<String> = lolcate::database_names(lolcate::lolcate_config_path());
            let database = "default";
            match lolcate::create_database(&database) {
                Ok(_) => println!("数据库创建成功"),
                Err(e) => {
                    eprintln!("创建数据库时发生错误: {}", e);
                    // 可以在这里添加更多错误处理逻辑
                    // 例如返回错误代码或进行重试
                }
            }
            //modify config file
            let _fn = lolcate::config_fn(&database);
            let mut f = fs::File::create(&_fn)?;
            f.write_all(replace_dirs_with_current().as_bytes())?;
        }
        // FIXME: create a periodic lol update task
        // lolcate::update_databases(databases).unwrap();
        //periodic update task.
        // update lolversion.
        // Spawn update task
        let update_task = tokio::spawn(run_updater(
            std::time::Duration::from_secs(30*60),
        ));
        // Session layer.
        //
        // This uses `tower-sessions` to establish a layer that will provide the session
        // as a request extension.
        let session_store = SqliteStore::new(self.db.clone());
        session_store.migrate().await?;

        let deletion_task = tokio::task::spawn(
            session_store
                .clone()
                .continuously_delete_expired(std::time::Duration::from_secs(60)),
        );

                // 5. 构建 Router
        let app = self.build_router().await;   // ← 这里调用刚抽出来的函数
        // 获取本地活跃IP
        let mut active_ip :IpAddr = "127.0.0.1".parse().unwrap();
        let mut has_ipv4 = false;

        match getifaddrs() {
            Ok(interfaces) => {
                //println!("本地活跃IP地址:");
                for iface in interfaces {
                    // 检查接口是否活跃
                    if iface.flags.contains(getifaddrs::InterfaceFlags::RUNNING) {
                        // address 字段现在直接是 IpAddr 类型，无需 Option 匹配
                        let addr = iface.address;
                        
                        match addr {
                            IpAddr::V4(ipv4) => {
                                // 过滤回环地址
                                if !ipv4.is_loopback() {
                                    //println!("IPv4: {} (接口: {})", ipv4, iface.name.clone());
                                    has_ipv4 = true;
                                    //println!("use ipv4 address as default URL.");
                                }
                            }
                            IpAddr::V6(ipv6) => {
                                // 过滤回环地址和链路本地地址
                                if !ipv6.is_loopback() && !ipv6.is_unicast_link_local() {
                                    //println!("IPv6: {} (接口: {})", ipv6, iface.name.clone());
                                }
                            }
                        }
                    }
                }
            }
            Err(e) => {
                eprintln!("获取网络接口失败: {}", e);
            }
        } 

        match getifaddrs() {
            Ok(interfaces) => {
                println!("本地活跃IP地址:");
                for iface in interfaces {
                    // 检查接口是否活跃
                    if iface.flags.contains(getifaddrs::InterfaceFlags::RUNNING) {
                        // address 字段现在直接是 IpAddr 类型，无需 Option 匹配
                        let addr = iface.address;
                        
                        match addr {
                            IpAddr::V4(ipv4) => {
                                // 过滤回环地址
                                if !ipv4.is_loopback() {
                                    println!("IPv4: {} (接口: {})", ipv4, iface.name.clone());
                                    active_ip = addr;
                                    //iface_name = iface_clone;
                                }
                            }
                            IpAddr::V6(ipv6) => {
                                // 过滤回环地址和链路本地地址
                                if !ipv6.is_loopback() && !ipv6.is_unicast_link_local() && !has_ipv4 {
                                    active_ip = addr;
                                    //iface_name = iface.name.clone();
                                    println!("IPv6: {} (接口: {})", ipv6, iface.name.clone());
                                }
                            }
                        }
                    }
                }
            }
            Err(e) => {
                eprintln!("获取网络接口失败: {}", e);
            }
        } 
        //sniffer prom mode does not work, since no copy flow made by Linux. 
        // let mut sniffer_handler = tokio::task::spawn_blocking(move || sniffer::sniffer(iface_name.to_string()));

        let port = 18516;
        // 构建URL
        let url = format!("http://{}:{}", active_ip, port);


        // 在新线程中打开浏览器
        std::thread::spawn(move || {
            // 等待服务器启动
            std::thread::sleep(std::time::Duration::from_secs(1));
            

            
            // 使用opener crate打开浏览器
            if let Err(e) = open_browser(&url) {
                eprintln!("无法打开浏览器: {}", e);
                eprintln!("请手动访问: {}", url);
            } else {
                //println!("当前浏览器已启动，访问: {}", url);
            }
        });     
                // 启动服务器
        println!("Server listening on {}", config.address);
        let addr: std::net::SocketAddr = config.address.parse().expect("Invalid address");           
        let listener = tokio::net::TcpListener::bind(addr).await.unwrap();

        // Ensure we use a shutdown signal to abort the deletion task.
        axum::serve(listener, app.into_make_service_with_connect_info::<std::net::SocketAddr>())
            .with_graceful_shutdown(shutdown_signal(deletion_task.abort_handle()))
            .await?;

        deletion_task.await??;
        //sniffer_handler.await?;
        update_task.await??;
        //log::info!("Server shutdown");
        Ok(())
    }
/* ====== 私有：把原来 serve() 里拼 Router 的逻辑提出来 ====== */
    /// 仅构建 Router，不监听端口
    pub async fn build_router(&self) -> Router {
        // 1. 全局 Session 层（不变）
        let session_store = SqliteStore::new(self.db.clone());
        session_store.migrate().await.expect("session migrate");

        let key = Key::generate();
        let session_layer = SessionManagerLayer::new(session_store)
            .with_secure(false)
            .with_expiry(Expiry::OnInactivity(Duration::days(1)))
            .with_signed(key);

        // 2. 构建 AuthManagerLayer（全局生效）
        let backend = Backend::new(self.db.clone());
        let auth_manager_layer = AuthManagerLayerBuilder::new(backend, session_layer.clone())
            .build();

        // 3. 静态资源（不变）
        let font_service = ServiceBuilder::new()
            .layer(SetResponseHeaderLayer::overriding(
                CONTENT_TYPE,
                HeaderValue::from_static("font/woff2"),
            ))
            .service(ServeDir::new("fonts"));

        let assets = Router::new()
            .nest_service("/fonts", font_service)
            .nest_service("/assets", ServeDir::new("assets"));

        // 4. 登录路由：添加 AuthManagerLayer（关键！登录需要它）
        let auth_router = auth::router()
        
            .layer(auth_manager_layer.clone()); // 登录路由必须有 AuthManagerLayer

        // 5. Protected 路由：使用克隆的 AuthManagerLayer（无需重复构建）
        // 关键修正：protected 路由中间件顺序（按这个顺序加）
        // 关键：为 protected 路由添加完整中间件链，确保所有子路由（包括 /）都生效
    // 1. 构建完整的中间件链（顺序绝对不可变）
    let protected_middleware = ServiceBuilder::new()
        // 第一步：注入 AuthSession（必须最先）
        .layer(auth_manager_layer)
        // 第二步：验证登录（依赖 AuthSession）
        .layer(login_required!(Backend, login_url = "/login"))
        // 第三步：注入 CasbinVals（依赖 AuthSession）
        .layer(casbinauthz::AuthInjectLayer)
        // 第四步：权限校验（依赖 CasbinVals）
        .layer(middleware::from_fn(protected::casbin_middleware));

    // 2. 将中间件链应用到 protected 路由
    let protected = protected::router().await
        .layer(protected_middleware); // 用 ServiceBuilder 确保顺序

        // 6. 最终路由：全局添加 session_layer，合并所有路由
        Router::new()        
            .merge(assets)
            .route("/", axum::routing::get(showlove::get::show_love))
            .route("/showlovewall.html", axum::routing::get(showlove::get::show_love))
            .route("/pastebin", axum::routing::post(showlove::post::handle_pastebin))
            .route("/logs", axum::routing::get(log::get::log_lookup))
            .route("/system-settings", axum::routing::get(admin::get::sysset_setting))
            .route("/saveqr", axum::routing::post(admin::post::saveqr))
            .route("/qr", axum::routing::get(showlove::get::get_qrcode))
            .merge(auth_router) // 先合并登录路由（带 AuthManagerLayer）
            .merge(protected)
            .layer(MessagesManagerLayer)
            .layer(DefaultBodyLimit::max(10 * 1024 * 1024 * 1024))
            .layer(session_layer)// 全局 Session 层（所有路由都需要）
    }


}

async fn shutdown_signal(deletion_task_abort_handle: AbortHandle) {
    let ctrl_c = async {
        signal::ctrl_c()
            .await
            .expect("failed to install Ctrl+C handler");
    };

    #[cfg(unix)]
    let terminate = async {
        signal::unix::signal(signal::unix::SignalKind::terminate())
            .expect("failed to install signal handler")
            .recv()
            .await;
    };

    #[cfg(not(unix))]
    let terminate = std::future::pending::<()>();

    tokio::select! {
        _ = ctrl_c => { deletion_task_abort_handle.abort() },
        _ = terminate => { deletion_task_abort_handle.abort() },
    }
}

async fn run_updater(interval: std::time::Duration) -> anyhow::Result<()> {
    let mut ticker = tokio::time::interval(interval);
    
    loop {
        tokio::select! {
            _ = ticker.tick() => {
                let databases: Vec<String> = lolcate::database_names(lolcate::lolcate_config_path());
                lolcate::update_databases(databases).unwrap();
            }
        }
    }

}
